
#include "RoleAssigner.h"

#include <iostream>

#define ALPHA 0.5f

struct PlayerRoleScore {
    unsigned player_id;
    float score;
};



RoleAssigner& RoleAssigner::instance(void){
    static RoleAssigner role_assigner;
    return role_assigner;
}

RoleAssigner::RoleAssigner(){
}

RoleAssigner::~RoleAssigner(){
}

void RoleAssigner::updatePlayerRoleScores(unsigned player_id, std::map<RoleType, float> role_scores){
    if(player_role_scores.find(player_id) == player_role_scores.end()){
        createNewPlayerMap(player_id);
    }

    std::map<RoleType, float>::iterator it = role_scores.begin();
    while(it != role_scores.end()){
        float past_value = player_role_scores[player_id][it->first];
        player_role_scores[player_id][it->first] = (1.0f-ALPHA)*it->second + ALPHA*past_value;
        ++it;
    }

    recalculateRoles();
}

RoleType RoleAssigner::getBestRole(unsigned player_id){
    return role_assignment[player_id];
}

void RoleAssigner::createNewPlayerMap(unsigned player_id){
    std::map<RoleType, float> role_scores;
    role_scores[ATTACKER_ROLE] = 0.0f;
    role_scores[DEFENDER_ROLE] = 0.0f;
    role_scores[MARAUDER_ROLE] = 0.0f;
    player_role_scores[player_id] = role_scores;
}

void RoleAssigner::recalculateRoles(void){
    role_assignment.clear();

    std::list<unsigned> ordered_attackers = getOrderedRoleList(ATTACKER_ROLE);
    std::list<unsigned> ordered_defenders = getOrderedRoleList(DEFENDER_ROLE);
    std::list<unsigned> ordered_marauders = getOrderedRoleList(MARAUDER_ROLE);

    unsigned num_attackers = ordered_attackers.size()/3 + 1;
    unsigned num_defenders = ordered_defenders.size()/3 + 1;
    unsigned num_marauders = ordered_marauders.size() - (num_attackers+num_defenders);


    while(num_attackers > 0){
        if(ordered_attackers.empty()){ break; }
        unsigned candidate = ordered_attackers.front();
        if(role_assignment.find(candidate) == role_assignment.end()){
            role_assignment[candidate] = ATTACKER_ROLE;
            num_attackers--;
        }
        ordered_attackers.pop_front();
    }

    while(num_defenders > 0){
        if(ordered_defenders.empty()){ break; }
        unsigned candidate = ordered_defenders.front();
        if(role_assignment.find(candidate) == role_assignment.end()){
            role_assignment[candidate] = DEFENDER_ROLE;
            num_defenders--;
        }
        ordered_defenders.pop_front();
    }

    while(num_marauders > 0){
        if(ordered_marauders.empty()){ break; }
        unsigned candidate = ordered_marauders.front();
        if(role_assignment.find(candidate) == role_assignment.end()){
            role_assignment[candidate] = MARAUDER_ROLE;
            num_marauders--;
        }
        ordered_marauders.pop_front();
    }
}

std::list<unsigned> RoleAssigner::getOrderedRoleList(RoleType role_type){
    std::list<PlayerRoleScore> tmp;
    std::map<unsigned, std::map<RoleType, float> >::iterator it = player_role_scores.begin();
    while(it != player_role_scores.end()){
        PlayerRoleScore prs;
        prs.player_id = it->first;
        prs.score = it->second[role_type];

        tmp.push_back(prs);
        ++it;
    }

    std::list<unsigned> result;
    while(tmp.size() > 0){
        std::list<PlayerRoleScore>::iterator tmp_it = tmp.begin();
        std::list<PlayerRoleScore>::iterator highest_pos = tmp.begin();

        while(tmp_it != tmp.end()){
            if(tmp_it->score > highest_pos->score){
                highest_pos = tmp_it;
            }

            ++tmp_it;
        }

        result.push_back(highest_pos->player_id);
        tmp.erase(highest_pos);
    } 

    return result;
}

